package cn.gok.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 当前工具类的作用是解析Request中的请求数据。并将其封装到指定的实体类中
 */

public class ParseRequestParameterUtil {

    /**
     *用来解析 request中的数据， request中的数据中的存储格式为 Map<String, String[]>
     *     params : request中的请求数据
     *     aClass： 要封装的对象的类型
     * @return
     */
    public static Object parseRequestParam(Map<String, String[]> params, Class aClass){
        Object obj = null;

        try {
            obj = aClass.getConstructor().newInstance();


            //1、建立起 key 和 field的对应关系，并存储到一个map中，供以后使用
            //1.1 类中所有的属性
            Field[] fields = aClass.getDeclaredFields();
            //1.2 map中所的key
            Set<String> keySet = params.keySet();

            /*
               1.3
                并不是说map中所有的key  都能在类中找到对应的属性
                并不是说类中所有的属性，  在map中都有一个对应的key
             */

            //我们通过自定义的方法找出 map的key 和 类里对应的属性，并将对应的上的这些，存入map
            Map<String, Field> fieldNameMappingField = getExitsField(fields, keySet);



            /*
                2、 fieldNameMappingField 中的key是我们处理过的，也就是说，这里面的key一定类中存在的属性
                    我们现在只需要变量它，然后对类中对应的属性赋值即可
             */
            for (String fieldName : fieldNameMappingField.keySet()) {

                //2.1、根据属性名生成对应的set方法
                String setMethodName = concatSetMethodName(fieldName);

                //2.2、获取set方法
                //set方法中的参数类型，和属性的类型一致的
                Field field = fieldNameMappingField.get(fieldName);
                Method method = aClass.getMethod(setMethodName, field.getType());

                /*
                    2.3、执行此方法，为属性赋值
                            前端提交的数据格式为Map<String, String[]>
                        也就是说我们要判断一下，
                        如果 value部分的长度 =0,  说明这个提交该属性没值
                        如果 value部分的长度 =1, 说明提交的就是单个值
                        如果 value部分的长度 >1, 则说明前端提交的是复选框这样的数据

                        {
                            userName :[zhangsan]
                            password:[1243435]
                            scores:[12,18,20]
                        }
                 */
                String[] strings = params.get(fieldName);

                //调用set方法，进行赋值
                runSetMethod(method, field, strings, obj);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return obj;
    }

    private static void runSetMethod(Method method,Field field,String[] strings,Object obj) throws InvocationTargetException, IllegalAccessException, ParseException {
        if (strings.length == 1){
            //前端提交数据后， 我们统一拿到的都是String，但是属性可能是Integer 、Double、Boolean、Date、String这样的简单数据
            if (field.getType().equals(Integer.class) || field.getType().equals(int.class) ){
                if (strings[0] !=null && !"".equals(strings[0])){
                    Integer value = Integer.parseInt( strings[0]);
                    method.invoke(obj,value);
                }
            } else if (field.getType().equals(Byte.class)|| field.getType().equals(byte.class)){
                if (strings[0] !=null && !"".equals(strings[0])){
                    Byte value = Byte.parseByte( strings[0]);
                    method.invoke(obj,value);
                }
            } else if (field.getType().equals(Short.class)|| field.getType().equals(short.class)){
                if (strings[0] !=null && !"".equals(strings[0])){
                    Short value = Short.parseShort( strings[0]);
                    method.invoke(obj,value);
                }
            } else if (field.getType().equals(Long.class)|| field.getType().equals(long.class)){
                if (strings[0] !=null && !"".equals(strings[0])){
                    Long value = Long.parseLong( strings[0]);
                    method.invoke(obj,value);
                }
            }else if (field.getType().equals(Double.class)|| field.getType().equals(double.class)){
                if (strings[0] !=null && !"".equals(strings[0])){
                    Double value = Double.parseDouble( strings[0]);
                    method.invoke(obj,value);
                }
            }else if (field.getType().equals(Float.class)|| field.getType().equals(float.class)){
                if (strings[0] !=null && !"".equals(strings[0])){
                    Float value = Float.parseFloat( strings[0]);
                    method.invoke(obj,value);
                }
            }else if (field.getType().equals(Boolean.class) || field.getType().equals(boolean.class)){
                if (strings[0] !=null && !"".equals(strings[0])){
                    Boolean value = Boolean.parseBoolean(strings[0]);
                    method.invoke(obj,value);
                }
            }else if(field.getType().equals(Date.class)){
                if (strings[0] !=null && !"".equals(strings[0])){
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                    Date date = dateFormat.parse(strings[0]);
                    method.invoke(obj,date);
                }
            }else {
                method.invoke(obj,strings[0]);
            }
        }


//        else {
//
//            /*
//                如果strings 长度大于0 ，则表示多个数据
//                    这个时候我们的属性类型，可能是数组 ，也可能是集合
//                    我们要确定的是集合、数组中泛型的数据类型
//             */
//           if ( field.getType().isArray()){
//
//               field.getGenericType();
//
//           }else {
//
//           }
//        }
    }


    /**
     * @param fields  类中所有的属性
     * @param keys    map中所有的key
     * 建立起 key 和 field的对应关系，并存储到一个map中，供以后使用
     */
    private static Map<String, Field> getExitsField(Field[] fields, Set<String> keys){
        //存储map中的key 和 属性field之间的映射关系
        Map<String, Field> keyMappingField = new HashMap<>();

        //遍历所有的key
        for (String filedName : keys) {

            //判断map中的key  是否为类的一个属性， 然后我们还有拿到这个属性
            Field field = exitsField(fields, filedName);
            if ( field != null){
                keyMappingField.put(filedName,field);
            }
        }
        return keyMappingField;
    }


    /**
     * 判断属性是否在类中存在,
     * 如果属性存在，则返回具体的Field对象，
     * 不存在则返回null值
     * @return
     */
    private static Field exitsField(Field[] fields, String fieldName){
        Field field = null;
        for (int i = 0; i < fields.length; i++) {
            String name = fields[i].getName();
            if ( name.equals(fieldName)){
                field = fields[i];
                break;
            }
        }
        return field;
    }


    /**
     * 根据属性名拼接一个set方法
     *   比如 userName ， 拼接成setUserName
     * @return
     */
    private static String concatSetMethodName(String field){
        //首字母转大写
        char[] chars = field.toCharArray();
        chars[0] = (char) (chars[0] - 32);
        String newFieldName = new String(chars);
        //拼接set并返回
        return "set" + newFieldName;
    }

}
